package net.kem.utils.directorywatcher;

import java.io.File;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Pattern;



/**
 * This file processor tries to remove file that ends with ".zip" and is older than specified date or time offset.
 * @author Evgeny.Kurtser
 *
 */
public class OldZipFileRemover extends DirectoryWatcher {
	private Calendar _expiry;
	private int _calendarField;
	private int _offset;

	/**
	 * Creates new OldZipFileRemover that will try to remove file that ends with ".zip" and is older than <em>absolute</em> specified date.
	 * For example, if 'expiry' points on "Sep-01 2010, 14:00.00" then all the compressed files <strong>newer</strong> than this date will be never removed.
	 * @param directoryToWatch directory to be watched.
	 * @param expiry all files that ends with ".zip" and is older than 'expiry' will be removed.
	 * @param pattern Pattern to filter files in the directory. If <em>null</em>, then the default Pattern will be used.
	 * The default Pattern allows all files.
	 * @throws NullPointerException if supplied parameter is <em>null</em>.
	 */
	public OldZipFileRemover(String directoryToWatch, Calendar expiry, Pattern pattern) throws NullPointerException {
		this(new File(directoryToWatch), expiry, pattern);
	}

	/**
	 * Creates new OldZipFileRemover that will try to remove file that ends with ".zip" and is older than specified <em>relative</em> time offset.
	 * For example, if 'calendarField' is Calendar.DAY_OF_MONTH and 'offsetInSeconds' is -5 (i.e. 5 days back) then all the compressed files <strong>older</strong> than current time minus 5 days will be removed.
	 * @param directoryToWatch directory to be watched.
	 * @param calendarField units as defined in Calendar such like {@link Calendar#SECOND}, {@link Calendar#HOUR_OF_DAY} or {@link Calendar#DAY_OF_MONTH}.
	 * @param offset all files that ends with ".zip" and is older than (current time + 'offset') will be removed.
	 * @param pattern Pattern to filter files in the directory. If <em>null</em>, then the default Pattern will be used.
	 * The default Pattern allows all files.
	 * Note that you will usually use negative value of this parameter to define time offset to the past.
	 * @see Calendar#add(int, int)
	 */
	public OldZipFileRemover(String directoryToWatch, int calendarField, int offset, Pattern pattern) {
		this(new File(directoryToWatch), calendarField, offset, pattern);
	}

	/**
	 * Creates new OldZipFileRemover that will try to remove file that ends with ".zip" and is older than <em>absolute</em> specified date.
	 * For example, if 'expiry' points on "Sep-01 2010, 14:00.00" then all the compressed files <strong>newer</strong> than this date will be never removed.
	 * @param directoryToWatch directory to be watched.
	 * @param expiry all files that ends with ".zip" and is older than 'expiry' will be removed.
	 * @param pattern Pattern to filter files in the directory. If <em>null</em>, then the default Pattern will be used.
	 * The default Pattern allows all files.
	 * @throws NullPointerException if supplied parameter is <em>null</em>.
	 */
	public OldZipFileRemover(File directoryToWatch, Calendar expiry, Pattern pattern) throws NullPointerException {
		super(directoryToWatch, pattern);
		if(expiry == null) {
			throw new NullPointerException("\"expiry\" parameter cannot be null");
		}
		_expiry = expiry;
		_offset = 0;
	}

	/**
	 * Creates new OldZipFileRemover that will try to remove file that ends with ".zip" and is older than specified <em>relative</em> time offset.
	 * For example, if 'calendarField' is Calendar.DAY_OF_MONTH and 'offsetInSeconds' is -5 (i.e. 5 days back) then all the compressed files <strong>older</strong> than current time minus 5 days will be removed.
	 * @param directoryToWatch directory to be watched.
	 * @param calendarField units as defined in Calendar such like {@link Calendar#SECOND}, {@link Calendar#HOUR_OF_DAY} or {@link Calendar#DAY_OF_MONTH}.
	 * @param offset all files that ends with ".zip" and is older than (current time + 'offset') will be removed.
	 * Note that you will usually use negative value of this parameter to define time offset to the past.
	 * @param pattern Pattern to filter files in the directory. If <em>null</em>, then the default Pattern will be used.
	 * The default Pattern allows all files.
	 * @see Calendar#add(int, int)
	 */
	public OldZipFileRemover(File directoryToWatch, int calendarField, int offset, Pattern pattern) {
		super(directoryToWatch, pattern);
		_calendarField = calendarField;
		_offset = offset;
	}


	/**
	 * Calculates time offset if applicable.
	 * @return always true.
	 */
	protected boolean preProcess(File directoryToWatch) {
		super.preProcess(directoryToWatch);
		if(_offset != 0) {
			_expiry = Calendar.getInstance();
			_expiry.add(_calendarField, _offset);
		}
		return true;
	}

	/**
	 * Tries to remove the given file.
	 * @return <em>null</em> if the file was removed or original file if this file could not be removed.
	 */
	protected File processFile(File file) {
		long fileTimestamp = file.lastModified();
		boolean res = fileTimestamp < _expiry.getTimeInMillis();
		if(res) {
			res = file.delete();
			if(!res) {
				LOG.error("OldZipFileRemover: File " + file.getName() + " could not be deleted.");
			} else {
				if(_isDebugEnabled) {
					LOG.debug("OldZipFileRemover: File " + file.getName() + " was deleted.");
				}
			}
		} else {
			if(_isTraceEnabled) {
				String fileName = file.getName();
				String age = new Date(file.lastModified()).toString();
				LOG.trace("OldZipFileRemover: File " + fileName + ", " + age + " is too young.");
			}
		}
		return res? null: file;
	}

	/**
     * This implementation accepts files (not directories) that older than calculated expiry date.
     * @param  pathname  the abstract pathname to be tested.
     * @return  <code>true</code> if and only if <code>pathname</code> should be included.
     */
	@Override
	public boolean accept(File pathname) {
		boolean res = super.accept(pathname);
		if(_isTraceEnabled) {
			String fileName = pathname.getName();
			String age = new Date(pathname.lastModified()).toString();
			if(res) {
				LOG.trace("OldZipFileRemover: File " + fileName + ", " + age + " will be removed.");
			} else {
				LOG.trace("OldZipFileRemover: File " + fileName + ", " + age + " is too young.");
			}
		}
		return res;
	}

	/**
	 * This method is called after the {@link #processFile(File)} is invoked.
	 * This implementation does nothing.
	 * Note that if {@link #preProcess(File)} returns <em>false</em>, this method will not be invoked.
	 */
	protected void postProcess() {
		if(_offset != 0 && _isDebugEnabled) {
			LOG.debug("OldZipFileRemover: Current expiry limit was " + _expiry.getTime().toString());
		}
	}
}